/**
  @file drv_tbl_reg.c

  @date 2010-07-22

  @version v5.1

  The file implement driver IOCTL defines and macros
*/

#include "sal.h"
#include "usw/include/drv_common.h"
#include "usw/include/drv_error.h"
#include "usw/include/drv_chip_ctrl.h"
/**********************************************************************************
              Define Global declarations, Typedef, define and Data Structure
***********************************************************************************/


const uint8 _g_drv_usw_hw_size[17] = {0,1,2,4,4,8,8,8,8,16,16,16,16,16,16,16,16};

uint32
_drv_usw_consum_hw_addr_size(uint16 word_num)
{
    uint32 addr_word_num = 0;

#if (1 == SDK_WORK_PLATFORM)
    addr_word_num = word_num;
#else
    if (word_num <= 16)
    {
        addr_word_num = _g_drv_usw_hw_size[word_num];
    }
    else if (word_num <= 32)
    {
        addr_word_num = 32;
    }
    else if (word_num <= 64)
    {
        addr_word_num = 64;
    }
    else if (word_num <= 128)
    {
        addr_word_num = 128;
    }
    else if (word_num <= 256)
    {
        addr_word_num = 256;
    }
    else if (word_num <= 512)
    {
        addr_word_num = 512;
    }
    else if (word_num <= 1024)
    {
        addr_word_num = 1024;
    }
#endif

    return addr_word_num;
}


/*model use, sdk not use*/
int32
drv_usw_table_consum_hw_addr_size_per_index(uint8 lchip, tbls_id_t tbl_id, uint32 *hw_addr_size)
{

  *hw_addr_size = _drv_usw_consum_hw_addr_size(TABLE_ENTRY_SIZE(lchip, tbl_id)>>2);

    return DRV_E_NONE;

}

int32
drv_usw_get_field_offset(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id, uint32* w_offset, uint32 *b_offset)
{

    return DRV_E_NONE;
}
/*model*/



int32
drv_usw_get_tbl_index_base(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint16 *addr_offset)
{
    uint32 entry_num_per_addr = 0;


    if (DRV_TBL_INS_OFFSET(index))/*instance*/
    {
        *addr_offset = DRV_TBL_INS_OFFSET(index);
    }
    else if (TABLE_ADDR_NUM(lchip, tbl_id) > 1)
    {
        entry_num_per_addr = TABLE_MAX_INDEX(lchip, tbl_id);
         entry_num_per_addr = entry_num_per_addr/ TABLE_ADDR_NUM(lchip, tbl_id);
        *addr_offset = index / entry_num_per_addr;
    }
    else
    {
        *addr_offset = 0;
    }

#if (1 == SDK_WORK_PLATFORM) && (defined(TSINGMA_MX) || defined(TSINGMA_GX) || defined(ARCTIC))
    *addr_offset += TABLE_ADDR_NUM(lchip, tbl_id);
#endif

    return DRV_E_NONE;
}

fields_t *
drv_usw_find_field(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id)
{
    fields_t *p_fld = NULL;

    if (lchip >= DRV_MAX_CHIP_NUM || !p_drv_master[lchip]->init_done)
    {
        return NULL;
    }
    if (!(CHK_TABLE_ID_VALID(lchip, tbl_id)))
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d, fieldID: %d\n", tbl_id, field_id);
        if (TABLE_NAME(lchip, tbl_id))
        {
            DRV_DBG_INFO("ERROR! INVALID TblName:%s\n", TABLE_NAME(lchip, tbl_id));
        }
        return NULL;
    }

    p_fld = TABLE_FIELD_INFO_PTR(lchip, tbl_id) + field_id;


    if (0 == TABLE_FIELD_NUM(lchip, tbl_id) || field_id >= TABLE_FIELD_NUM(lchip, tbl_id) || 0 == p_fld->bits)
    {
        DRV_DBG_INFO("ERROR! (drv_usw_mem_get_field): memID-%d, field-%d is not supported\n", tbl_id, field_id);
        return NULL;
    }

    return p_fld;
}


/**
 @brief
*/
int32
drv_usw_get_tbl_string_by_id(uint8 lchip, tbls_id_t tbl_id, char* name)
{
    DRV_INIT_CHECK(lchip);
    if (!name)
    {
        return DRV_E_INVALID_PARAMETER;
    }
    if (0 == TABLE_FIELD_NUM(lchip, tbl_id))
    {
        return DRV_E_NONE;
    }

    if (tbl_id < MaxTblId_t)
    {
         sal_strcpy(name, TABLE_NAME(lchip, tbl_id));
         return DRV_E_NONE;
    }

    return DRV_E_INVALID_TBL;
}

/**
 @brief
*/
int32
drv_usw_get_field_string_by_id(uint8 lchip, tbls_id_t tbl_id, fld_id_t field_id, char* name)
{
#ifndef DRV_DS_LITE
    fields_name_t* ptr_field_name = NULL;

    if (!name)
    {
        return DRV_E_INVALID_PARAMETER;
    }
    DRV_INIT_CHECK(lchip);
    if (0 == TABLE_FIELD_NUM(lchip, tbl_id) || field_id >= TABLE_FIELD_NUM(lchip, tbl_id))
    {
        DRV_DBG_INFO("ERROR! (drv_usw_mem_get_field): memID-%d, field-%d is not supported\n", tbl_id, field_id);
        return DRV_E_INVALID_FLD;
    }

    ptr_field_name = p_drv_master[lchip]->p_tbl_name[p_drv_master[lchip]->p_tbl_mapping[tbl_id]].fields_name + field_id;
    sal_strcpy(name, ptr_field_name->ptr_field_name);
#endif

    return DRV_E_NONE;
}

/**
 @brief
*/
int32
drv_usw_get_tbl_id_by_string(uint8 lchip, tbls_id_t* tbl_id, char* name)
{
    tbls_id_t tmp_tableid = 0;
    DRV_INIT_CHECK(lchip);

    /* This is so inefficient Code, need to consider to optimize it, add by zhouw??? */
    for (tmp_tableid = 0; tmp_tableid < MaxTblId_t; tmp_tableid++)
    {
        if (0 == TABLE_INFO(lchip, tmp_tableid).byte)
        {
            continue;
        }
        if (0 == sal_strcasecmp(name, TABLE_NAME(lchip, tmp_tableid)))
        {
            *tbl_id = tmp_tableid;
            return DRV_E_NONE;
        }
    }

    DRV_DBG_INFO("%% Not Find the TableID!! tableName: %s\n", name);

    return DRV_E_INVALID_TBL;
}


int32
drv_usw_get_field_id_by_string(uint8 lchip, tbls_id_t tbl_id, fld_id_t* field_id, char* name)
{
#ifndef DRV_DS_LITE
    fields_t* ptr_field_info = NULL;    
    uint32 tmp_index = 0;
    DRV_INIT_CHECK(lchip);

    if (!(CHK_TABLE_ID_VALID(lchip, tbl_id)))
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d\n", tbl_id);
        if (TABLE_NAME(lchip, tbl_id))
        {
            DRV_DBG_INFO("ERROR! INVALID TblName:%s\n", TABLE_NAME(lchip, tbl_id));
        }
        return DRV_E_INVALID_TBL;
    }

    ptr_field_info = TABLE_FIELD_INFO_PTR(lchip, tbl_id);

    for (tmp_index = 0; tmp_index < TABLE_FIELD_NUM(lchip, tbl_id); tmp_index++)
    {
        if (ptr_field_info[tmp_index].bits == 0)
        {
            continue;
        }
        if (0 == sal_strcasecmp(name, FIELD_NAME(lchip, tbl_id, tmp_index)))
        {
            *field_id = ptr_field_info[tmp_index].field_id;
            return DRV_E_NONE;
        }
    }

    DRV_DBG_INFO("%% Not Find the FieldID!! tableId: %d; Fieldname: %s\n", tbl_id, name);
#endif
    return DRV_E_INVALID_FLD;
}

int32
drv_usw_get_field_id_by_sub_string(uint8 lchip, tbls_id_t tbl_id, fld_id_t* field_id, char* name)
{
#ifndef DRV_DS_LITE
    fields_t* ptr_field_info = NULL;
    uint32 tmp_index = 0;
    DRV_INIT_CHECK(lchip);

    if (!(CHK_TABLE_ID_VALID(lchip, tbl_id)))
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d\n", tbl_id);
        if (TABLE_NAME(lchip, tbl_id))
        {
            DRV_DBG_INFO("ERROR! INVALID TblName:%s\n", TABLE_NAME(lchip, tbl_id));
        }
        return DRV_E_INVALID_TBL;
    }

    ptr_field_info = TABLE_FIELD_INFO_PTR(lchip, tbl_id);
    for (tmp_index = 0; tmp_index < TABLE_FIELD_NUM(lchip, tbl_id); tmp_index++)
    {
        if (0 == ptr_field_info[tmp_index].bits)
        {
            continue;
        }
        if (0 == sal_strcasecmp(name, FIELD_NAME(lchip, tbl_id, tmp_index)))
        {
            *field_id = ptr_field_info[tmp_index].field_id;
          /*   DRV_DBG_INFO("%% The Fieldname is found by accuracy matching !! tableId: %d; Fieldname: % s \n", tbl_id, name);*/
            return DRV_E_NONE;
        }
    }

    for (tmp_index = 0; tmp_index < TABLE_FIELD_NUM(lchip, tbl_id); tmp_index++)
    {
        if (0 == ptr_field_info[tmp_index].bits)
        {
            continue;
        }
        if (NULL != sal_strstr((FIELD_NAME(lchip, tbl_id, tmp_index)), name))
        {
            *field_id = ptr_field_info[tmp_index].field_id;
          /*   DRV_DBG_INFO("%% The Fieldname is found by fuzzy matching !! tableId: %d; Fieldname: % s \n", tbl_id, name);*/
            return DRV_E_NONE;
        }
    }
#endif
    /*DRV_DBG_INFO("%% Not Find the FieldID!! tableId: %d; Fieldname: %s\n", tbl_id, name);*/

    return DRV_E_INVALID_FLD;
}

/*used for field like DsSrcPort_gAcl_0_aclLabel_f, key_str is _0_*/
uint32
drv_usw_get_field_id_by_name(uint8 lchip, uint8 lkup_id, uint32 tbl_id, char* key_str, char* field_name)
{
#ifndef DRV_DS_LITE
    uint32 field_id;
    uint8  loop = 0;
    uint8  key_str_pos = 0;
    uint8  lkup_id_cnt = 0;
    uint8  key_str_len = sal_strlen(key_str);
    char new_field_name[64] = "";
    char *key_str_find = sal_strstr(field_name, key_str);
    fields_t* ptr_field_info = NULL;
    uint32 tmp_index = 0;

#define DRV_C_IS_NUM(c)     ((c)>='0' && (c)<='9')

    DRV_INIT_CHECK(lchip);
    if (!(CHK_TABLE_ID_VALID(lchip, tbl_id)))
    {
        DRV_DBG_INFO("ERROR! INVALID TblID or fieldID! TblID: %d\n", tbl_id);
        if (TABLE_NAME(lchip, tbl_id))
        {
            DRV_DBG_INFO("ERROR! INVALID TblName:%s\n", TABLE_NAME(lchip, tbl_id));
        }
        return DRV_INVALID_FIELD_ID;
    }

    if ((key_str_find == NULL) || (sal_strlen(key_str)>8) || (sal_strlen(field_name)>64))
    {
        return DRV_INVALID_FIELD_ID;
    }

    /*lkup for num*/
    for (loop=0; loop<key_str_len; loop++)
    {
        if (DRV_C_IS_NUM(key_str[loop]))
        {
            break;
        }
    }

    key_str_pos = (uint8)(key_str_find-field_name);
    sal_memcpy(new_field_name, field_name, key_str_pos+loop);
    if (lkup_id>=10)
    {
        new_field_name[key_str_pos+loop+(lkup_id_cnt++)] = lkup_id/10 + '0';
        lkup_id = lkup_id%10;
    }
    new_field_name[key_str_pos+loop+(lkup_id_cnt++)] = lkup_id + '0';
    sal_memcpy(&new_field_name[key_str_pos+loop+lkup_id_cnt], &field_name[key_str_pos+loop+1], sal_strlen(field_name)-key_str_pos-1);

    ptr_field_info = TABLE_FIELD_INFO_PTR(lchip, tbl_id);
    for (tmp_index = 0; tmp_index < TABLE_FIELD_NUM(lchip, tbl_id); tmp_index++)
    {
        if (0 == ptr_field_info[tmp_index].bits)
        {
            continue;
        }
        if (0 == sal_strcasecmp(new_field_name, FIELD_NAME(lchip, tbl_id, tmp_index)))
        {
            field_id = ptr_field_info[tmp_index].field_id;
            return field_id;
        }
    }
#endif
    return DRV_INVALID_FIELD_ID;
}

inline int32
drv_usw_table_get_dyn_hw_addr(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint32* hw_addr)
{

    uint32 entry_offset = 0;
    uint32 hw_data_base = 0;
    uint32 map_index = 0;
    uint16  addr_offset = 0;
    uint8  blk_id = 0;
    uint8 i = 0;

#if (1 == SDK_WORK_PLATFORM)
    addr_offset += TABLE_ADDR_NUM(lchip, tbl_id);
    entry_offset = TABLE_INFO(lchip, tbl_id).byte;
#else
    entry_offset = TABLE_INFO(lchip, tbl_id).entry_offset;
#endif

    for (i = 0; i < DYNAMIC_TABLE_BLK_NUM(lchip, tbl_id); i++)
    {
        if (index <= DYNAMIC_TABLE_END(lchip, tbl_id, i))
        {
            blk_id = DYNAMIC_TABLE_BLK_ID(lchip, tbl_id, i);
            hw_data_base = DYNAMIC_DATA_BASE(lchip, tbl_id, blk_id, addr_offset);
            break;
        }
    }

    if (p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)
    {
        if (DYNAMIC_TABLE_UNIT_NUM(lchip, tbl_id))
        { 
#if (1 == SDK_WORK_PLATFORM) 
            if ((tbl_id == DsXLookup0HashKey_t || tbl_id == DsXLookup0MutationHashKey_t) && 
                (blk_id == DRV_FTM_SRAM0 || blk_id == DRV_FTM_SRAM1 || blk_id == DRV_FTM_SRAM2 || blk_id == DRV_FTM_SRAM3))
            {
                entry_offset = _drv_usw_consum_hw_addr_size(DYNAMIC_12W_MODE) * DRV_BYTES_PER_WORD;
                *hw_addr = hw_data_base + ((DYNAMIC_ACCESS_INDEX(lchip, tbl_id, index) - DYNAMIC_START_INDEX(lchip, tbl_id, blk_id)) / 4)*entry_offset;
            }
            else
            {
                entry_offset = (_drv_usw_consum_hw_addr_size(DYNAMIC_ACCESS_MODE(lchip, tbl_id)&0xFF) << 2);
                map_index = ((DYNAMIC_TABLE_RW_INDEX(lchip, tbl_id, index) - DYNAMIC_TABLE_START(lchip, tbl_id, i)) / DYNAMIC_TABLE_UNIT_NUM(lchip, tbl_id));
                *hw_addr = hw_data_base + map_index*entry_offset;
            }
#else
        entry_offset = (_drv_usw_consum_hw_addr_size(DYNAMIC_ACCESS_MODE(lchip, tbl_id)&0xFF) << 2);  
        map_index = ((DYNAMIC_TABLE_RW_INDEX(lchip, tbl_id, index) - DYNAMIC_TABLE_START(lchip, tbl_id, i)) / DYNAMIC_TABLE_UNIT_NUM(lchip, tbl_id));
        *hw_addr = hw_data_base + map_index*entry_offset;
#endif
        }
        else
        {
            *hw_addr = hw_data_base + (index - DYNAMIC_TABLE_START(lchip, tbl_id, i)) * entry_offset;

        }
    }
    else
    {
        if (DYNAMIC_ACCESS_MODE(lchip, tbl_id) == DYNAMIC_8W_MODE || DYNAMIC_ACCESS_MODE(lchip, tbl_id) == DYNAMIC_16W_MODE)
        {
            *hw_addr = hw_data_base + ((index - DYNAMIC_TABLE_START(lchip, tbl_id, i)) <<4);
        }
        else
        {
            *hw_addr = hw_data_base + (index - DYNAMIC_TABLE_START(lchip, tbl_id, i)) * entry_offset;

        }
    }    

    return 0;
}

inline int32
drv_usw_table_get_static_hw_addr(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint32* hw_addr)
{
    uint32 max_idx = 0;
    uint32 entry_offset = 0;
    uint32 hw_data_base = 0;
    uint32 map_index = 0;    
    uint16  addr_offset = 0;

   max_idx = TABLE_INFO(lchip, tbl_id).entry;
   if (DRV_TBL_INS_OFFSET(index))/*instance*/
    {
        addr_offset = DRV_TBL_INS_OFFSET(index);
        map_index = DRV_TBL_INS_INDEX(index);
    }
    else if (TABLE_ADDR_NUM(lchip, tbl_id) > 1)
    {
         entry_offset = max_idx / TABLE_ADDR_NUM(lchip, tbl_id);
         addr_offset = index / entry_offset;
#if (SDK_WORK_PLATFORM == 1)
         map_index = index % (max_idx / ((p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)?TABLE_ADDR_NUM(lchip, tbl_id):1));
#else
         map_index = index % (max_idx / TABLE_INFO(lchip, tbl_id).addr_num);
#endif
    }
    else
    {
        addr_offset = 0;
#if (SDK_WORK_PLATFORM == 1)
        map_index = index % (max_idx / ((p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)?TABLE_ADDR_NUM(lchip, tbl_id):1));
#else
        map_index = index % (max_idx / TABLE_INFO(lchip, tbl_id).addr_num);
#endif
    }

#if (1 == SDK_WORK_PLATFORM)
    addr_offset += TABLE_ADDR_NUM(lchip, tbl_id);
    entry_offset = TABLE_INFO(lchip, tbl_id).byte;
#else
    entry_offset = TABLE_INFO(lchip, tbl_id).entry_offset;
#endif


    hw_data_base = (TABLE_INFO(lchip, tbl_id).addrs[addr_offset]);

    *hw_addr = hw_data_base + map_index *entry_offset;


     /*return entry offset*/
    return 0;
}

inline int32
drv_usw_table_get_tcam_ad_hw_addr1(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint32* hw_addr)
{
    uint32 hw_data_base = 0;
    uint16 addr_offset = 0;
    uint8 entry_offset = 0;
    uint8 i = 0;
    uint8 blk_id = 0;

    entry_offset = TABLE_INFO(lchip, tbl_id).entry_offset;
    if (p_drv_master[lchip]->dev_type >= DRV_ARCTIC || TCAM_MODULE_LPM != TCAM_KEY_MODULE(lchip, tbl_id))
    {
        *hw_addr = TABLE_EXT_INFO(lchip, tbl_id).addrs[addr_offset] + index * entry_offset;
    }
    else
    {
        for (i = 0; i < TCAM_TABLE_BLK_NUM(lchip, tbl_id); i++)
        {
            if (index <= TCAM_TABLE_END(lchip, tbl_id, i))
            {

                blk_id = TCAM_TABLE_BLK_ID(lchip, tbl_id, i);
                hw_data_base = TCAM_DATA_BASE(lchip, tbl_id, blk_id, addr_offset);
                break;
            }
        }
        *hw_addr = hw_data_base + (index - TCAM_TABLE_START(lchip, tbl_id, i)) * entry_offset;
    }

    return 0;
}

inline int32
drv_usw_table_get_tcam_ad_hw_addr(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint32* hw_addr)
{
    uint32 tbl_type = 0;
    uint32 hw_data_base = 0;
    uint32 map_index = 0;    
    uint16 addr_offset = 0;
    uint8 base_key_type;
    uint8 mapped_blk_id;
    uint8 i = 0;
    uint8 blk_id = 0;
    uint8 entry_offset = 0;

#if (1 == SDK_WORK_PLATFORM)
    addr_offset += TABLE_ADDR_NUM(lchip, tbl_id);
    entry_offset = TABLE_INFO(lchip, tbl_id).byte;
#else
    entry_offset = TABLE_INFO(lchip, tbl_id).entry_offset;
#endif

    tbl_type = (TABLE_EXT_INFO_PTR(lchip, tbl_id))?TABLE_EXT_INFO_TYPE(lchip, tbl_id):DRV_TABLE_TYPE_NORMAL;

    for (i = 0; i < TCAM_TABLE_BLK_NUM(lchip, tbl_id); i++)
    {
        if ((index >= TCAM_TABLE_START(lchip, tbl_id, i)) && (index <= TCAM_TABLE_END(lchip, tbl_id, i)))
        {

            blk_id = TCAM_TABLE_BLK_ID(lchip, tbl_id, i);
            hw_data_base = TCAM_DATA_BASE(lchip, tbl_id, blk_id, addr_offset);
            break;
        }
    }
    
    /*
        tcam key and AD is 1:1, so use tcam key's index_map.
        the index_map is based on 80 bits, need to convert to 80 bits unit before mappping and convert to 160 bit unit after mapping.
    */
    base_key_type = (tbl_type == DRV_TABLE_TYPE_TCAM_AD)?DRV_FTM_TCAM_KEY0 : DRV_FTM_LPM_TCAM_KEY0;
    mapped_blk_id = base_key_type + blk_id;
    if(p_drv_master[lchip]->p_mem_info[mapped_blk_id].index_map)
    {
        map_index = (tbl_type == DRV_TABLE_TYPE_TCAM_AD && TABLE_EXT_TYPE(lchip, tbl_id) != 2) ? ((index - TCAM_TABLE_START(lchip, tbl_id, i))<<1) : (index - TCAM_TABLE_START(lchip, tbl_id, i));
        map_index = p_drv_master[lchip]->p_mem_info[mapped_blk_id].index_map[map_index];
        map_index = (tbl_type == DRV_TABLE_TYPE_TCAM_AD && TABLE_EXT_TYPE(lchip, tbl_id) != 2) ? map_index>>1 : map_index;
        *hw_addr = hw_data_base + (map_index)* entry_offset;
    }
    else
    {
        *hw_addr = hw_data_base + (index - TCAM_TABLE_START(lchip, tbl_id, i)) * entry_offset;
    }

    return 0;
}

/* Get hardware address according to tablid + index + data/mask flag (only tcam key) */
STATIC int32
_drv_usw_table_get_tcam_hw_addr(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint32* hw_addr, uint32 flag)
{
    uint16 addr_offset = 0;
    uint32 blk_id = 0, blk_num = 0;
    uint32 addr_base = 0;
    uint32 map_index = 0;
    uint32 is_data = flag&0x1;
    uint32 tbl_type = (TABLE_EXT_INFO_PTR(lchip, tbl_id))?TABLE_EXT_INFO_TYPE(lchip, tbl_id):DRV_TABLE_TYPE_NORMAL;

    if (tbl_type == DRV_TABLE_TYPE_TCAM)
    {
        blk_num = (TCAM_KEY_MODULE(lchip, tbl_id) == TCAM_MODULE_LPM) ? DRV_CONST(DRV_MAX_LPM_TCAM_NUM) : DRV_CONST(DRV_MAX_NOR_TCAM_NUM);
       do
        {
            DRV_IF_ERROR_RETURN(drv_usw_get_tbl_index_base(lchip, tbl_id, index, &addr_offset));

            if (!DRV_BMP_ISSET(TCAM_BITMAP(lchip, tbl_id), blk_id))
            {
                blk_id++;
                continue;
            }

            if ((index >= TCAM_START_INDEX(lchip, tbl_id, blk_id)) && (index <= TCAM_END_INDEX(lchip, tbl_id, blk_id)))
            {
                addr_base = is_data ? TCAM_DATA_BASE(lchip, tbl_id, blk_id, addr_offset) : TCAM_MASK_BASE(lchip, tbl_id, blk_id, addr_offset);
                map_index = index - TCAM_START_INDEX(lchip, tbl_id, blk_id);

                if (TCAM_KEY_MODULE(lchip, tbl_id) != TCAM_MODULE_LPM)
                {
                    *hw_addr = addr_base + TCAM_KEY_SIZE(lchip, tbl_id)/DRV_BYTES_PER_ENTRY*DRV_ADDR_BYTES_PER_ENTRY*map_index;
                }
                else
                {
                    *hw_addr = addr_base + TCAM_KEY_SIZE(lchip, tbl_id) * map_index;
                }
                break;
            }
            blk_id++;
        } while( blk_id < blk_num);
    }
    else if(tbl_type == DRV_TABLE_TYPE_STATIC_TCAM_KEY)
    {
        if ((index >= TCAM_START_INDEX(lchip, tbl_id, 0)) && (index <= TCAM_END_INDEX(lchip, tbl_id, 0)))
        {
            addr_base = is_data ? TCAM_DATA_BASE(lchip, tbl_id, 0, 0) : TCAM_MASK_BASE(lchip, tbl_id, 0, 0);
            map_index = index;

            *hw_addr = addr_base + TCAM_KEY_SIZE(lchip, tbl_id) * map_index;
        }
    }

    return DRV_E_NONE;
}

/* Get hardware address according to tablid + index
    flag: for tcam, 0-mask, 1-data
          for sram, 0-not dump, 1-dump
 */
int32
drv_usw_table_get_hw_addr(uint8 lchip, tbls_id_t tbl_id, uint32 index, uint32* hw_addr, uint32 flag)
{
    uint32 tbl_type = (TABLE_EXT_INFO_PTR(lchip, tbl_id))?TABLE_EXT_INFO_TYPE(lchip, tbl_id):DRV_TABLE_TYPE_NORMAL;
    if ((tbl_type == DRV_TABLE_TYPE_TCAM) || (tbl_type == DRV_TABLE_TYPE_STATIC_TCAM_KEY))
    {
        _drv_usw_table_get_tcam_hw_addr(lchip, tbl_id, index, hw_addr, flag);
    }
    else if (tbl_type == DRV_TABLE_TYPE_DYNAMIC || tbl_type == DRV_TABLE_TYPE_MIXED)
    {
        drv_usw_table_get_dyn_hw_addr(lchip, tbl_id, index, hw_addr);
    }
    else if (tbl_type == DRV_TABLE_TYPE_TCAM_AD || tbl_type == DRV_TABLE_TYPE_TCAM_LPM_AD || tbl_type == DRV_TABLE_TYPE_TCAM_NAT_AD)
    {
#if (0 == SDK_WORK_PLATFORM)
        if (p_drv_master[lchip]->dev_type >= DRV_TSINGMA_MX)
        {
            drv_usw_table_get_tcam_ad_hw_addr1(lchip, tbl_id, index, hw_addr);
        }
        else
#endif
        {
            drv_usw_table_get_tcam_ad_hw_addr(lchip, tbl_id, index, hw_addr);
        }
    }
    else
    {
        drv_usw_table_get_static_hw_addr(lchip, tbl_id, index, hw_addr);
    }

    return DRV_E_NONE;
}

/**
  @driver get table type interface
*/
uint32
drv_usw_get_table_type (uint8 lchip, tbls_id_t tb_id)
{
    return (TABLE_EXT_INFO_PTR(lchip, tb_id))?TABLE_EXT_INFO_TYPE(lchip, tb_id):DRV_TABLE_TYPE_NORMAL;
}


int32 drv_usw_mutex_set_lock(uint8 lchip, uint32 lock_id, uint32 mutex_data_addr, uint32 mutex_mask_addr)
{
    uint32 tmp_val32[2] = {0, 0xffffffff};

    (void)drv_usw_chip_read(lchip, mutex_data_addr, &tmp_val32[0]);
    tmp_val32[0] |= (1U << lock_id);
    tmp_val32[1] &= ~(1U << lock_id);
    drv_usw_chip_write(lchip, mutex_data_addr, tmp_val32[0]);
    drv_usw_chip_write(lchip, mutex_mask_addr, tmp_val32[1]);

    (void)drv_usw_chip_read(lchip, mutex_data_addr, &tmp_val32[0]);
    if ((tmp_val32[0] >> lock_id) & 0x1)
    {
        return DRV_E_NONE;  /* obtain success */
    }
    else
    {
        return DRV_E_OCCPANCY;
    }
}

int32 drv_usw_mutex_set_unlock(uint8 lchip, uint32 lock_id, uint32 mutex_data_addr, uint32 mutex_mask_addr)
{
    uint32 tmp_val32[2] = {0, 0xffffffff};

    (void)drv_usw_chip_read(lchip, mutex_data_addr, &tmp_val32[0]);
    tmp_val32[0] &= ~(1U << lock_id);
    tmp_val32[1] &= ~(1U << lock_id);
    drv_usw_chip_write(lchip, mutex_data_addr, tmp_val32[0]);
    drv_usw_chip_write(lchip, mutex_mask_addr, tmp_val32[1]);

    (void)drv_usw_chip_read(lchip, mutex_data_addr, &tmp_val32[0]);
    if ((tmp_val32[0] >> lock_id) & 0x1)
    {
        return DRV_E_OCCPANCY;
    }
    else
    {
        return DRV_E_NONE;
    }
}

int32 drv_usw_mcu_lock(uint8 lchip, uint32 lock_id, uint8 mcu_id)
{
    int32  ret = 0;
    uint32 tmp_val32 = 0;
    uint32 lock_stat = 0;
    uint32 mutex_data_addr = 0;
    uint32 mutex_mask_addr = 0;
    uint32 timeout = DRV_CMD_TIMEOUT;
#ifdef EMULATION_ENV
return DRV_E_NONE;
#endif
    /*1. para check*/
    if ((DRV_MCU_LOCK_NONE == lock_id) || (p_drv_master[lchip]->wb_status == DRV_WB_STATUS_RELOADING))
    {
        return DRV_E_NONE;
    }
    if (1 == SDK_WORK_PLATFORM)
    {
        return DRV_E_NONE;
    }
    if (DRV_MCU_LOCK_MAX <= lock_id)
    {
        return DRV_E_EXCEED_MAX_SIZE;
    }

    /*2. get mutex address*/
    if(DRV_GET_MCU_ADDR)
    {
        DRV_GET_MCU_ADDR(mcu_id, &mutex_data_addr, &mutex_mask_addr);
    }
    else return DRV_E_INVALID_PTR;

    /*3. lock status check*/
    (void)drv_usw_chip_read(lchip, mutex_data_addr, &tmp_val32);
    lock_stat = (tmp_val32 >> lock_id) & 0x1;
    if(lock_stat)
    {
        return DRV_E_NONE;
    }

    /*4. mutex operation*/
    ret = drv_usw_mutex_set_lock(lchip, lock_id, mutex_data_addr, mutex_mask_addr);
    while((DRV_E_OCCPANCY == ret) && (--timeout))
    {
        ret = drv_usw_mutex_set_lock(lchip, lock_id, mutex_data_addr, mutex_mask_addr);
        if (DRV_E_NONE == ret)
        {
            break;
        }
    }

    /*5. success check*/
    if(DRV_E_NONE == ret)
    {
        return DRV_E_NONE;
    }
    else
    {
        return DRV_E_TIME_OUT;
    }
}

int32 drv_usw_mcu_unlock(uint8 lchip, uint32 lock_id, uint8 mcu_id)
{
    int32  ret = 0;
    uint32 tmp_val32 = 0;
    uint32 lock_stat = 0;
    uint32 mutex_data_addr = 0;
    uint32 mutex_mask_addr = 0;
    uint32 timeout = DRV_CMD_TIMEOUT;
#ifdef EMULATION_ENV
return DRV_E_NONE;
#endif
    /*1. para check*/
    if ((DRV_MCU_LOCK_NONE == lock_id) || (p_drv_master[lchip]->wb_status == DRV_WB_STATUS_RELOADING))
    {
        return DRV_E_NONE;
    }
    if (1 == SDK_WORK_PLATFORM)
    {
        return DRV_E_NONE;
    }
    if (DRV_MCU_LOCK_MAX <= lock_id)
    {
        return DRV_E_EXCEED_MAX_SIZE;
    }

    /*2. get mutex address*/
    if(DRV_GET_MCU_ADDR)
    {
        DRV_GET_MCU_ADDR(mcu_id, &mutex_data_addr, &mutex_mask_addr);
    }
    else return DRV_E_INVALID_PTR;

    /*3. lock status check*/
    (void)drv_usw_chip_read(lchip, mutex_data_addr, &tmp_val32);
    lock_stat = (tmp_val32 >> lock_id) & 0x1;
    if(!lock_stat)
    {
        return DRV_E_NONE;
    }

    /*4. mutex operation*/
    ret = drv_usw_mutex_set_unlock(lchip, lock_id, mutex_data_addr, mutex_mask_addr);
    while((DRV_E_OCCPANCY == ret) && (--timeout))
    {
        ret = drv_usw_mutex_set_unlock(lchip, lock_id, mutex_data_addr, mutex_mask_addr);
        if (DRV_E_NONE == ret)
        {
            break;
        }
    }

    /*5. success check*/
    if(DRV_E_NONE == ret)
    {
        return DRV_E_NONE;
    }
    else
    {
        return DRV_E_TIME_OUT;
    }
}

int32 drv_usw_mcu_tbl_lock(uint8 lchip, tbls_id_t tbl_id, uint32 op)
{
    uint8  mcu_id = 0xff;
    uint32 lock   = DRV_MCU_LOCK_NONE;
#ifdef EMULATION_ENV
return DRV_E_NONE;
#endif

    if(DRV_GET_MCU_LOCK_ID)
    {
        DRV_GET_MCU_LOCK_ID(lchip, tbl_id, &mcu_id, &lock);
    }
    else return DRV_E_INVALID_PTR;

    DRV_IF_ERROR_RETURN(drv_usw_mcu_lock(lchip, lock, mcu_id));

    return DRV_E_NONE;
}

int32 drv_usw_mcu_tbl_unlock(uint8 lchip, tbls_id_t tbl_id, uint32 op)
{
    uint8  mcu_id = 0xff;
    uint32 lock   = DRV_MCU_LOCK_NONE;
#ifdef EMULATION_ENV
return DRV_E_NONE;
#endif

    if(DRV_GET_MCU_LOCK_ID)
    {
        DRV_GET_MCU_LOCK_ID(lchip, tbl_id, &mcu_id, &lock);
    }
    else return DRV_E_INVALID_PTR;

    DRV_IF_ERROR_RETURN(drv_usw_mcu_unlock(lchip, lock, mcu_id));

    return DRV_E_NONE;
}

